/*
 * Copyright 2007-2008 Andrew O'Malley
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


package ws.quokka.plugin.scala;

import org.apache.tools.ant.taskdefs.Available;
import org.apache.tools.ant.taskdefs.Java;
import org.apache.tools.ant.types.FileSet;
import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.types.resources.FileResource;

import ws.quokka.core.bootstrap_util.Logger;
import ws.quokka.core.plugin_spi.Resources;
import ws.quokka.core.plugin_spi.support.AntUtils;
import ws.quokka.core.plugin_spi.support.ResourcesList;
import ws.quokka.core.plugin_spi.support.TypedProperties;

import ws.quokka.plugin.devreport.DevReportHelper;

import java.io.File;

import java.util.Iterator;


/**
 * ScalaDocsHelper generates scaladoc reports using either scaladoc or vscaladoc.
 */
public class ScalaDocsHelper {
    //~ Static fields/initializers -------------------------------------------------------------------------------------

    private static final String CLASSPATH = "classpath";

    //~ Instance fields ------------------------------------------------------------------------------------------------

    private DevReportHelper helper;
    private TypedProperties properties;
    private Resources resources;
    private ScalaPlugin plugin;
    private AntUtils utils;

    //~ Constructors ---------------------------------------------------------------------------------------------------

    public ScalaDocsHelper(ScalaPlugin plugin, Resources resources, TypedProperties properties, Logger log) {
        helper = new DevReportHelper(resources, properties, log);
        this.properties = properties;
        this.resources = resources;
        this.plugin = plugin;
        utils = new AntUtils(resources.getProject());
    }

    //~ Methods --------------------------------------------------------------------------------------------------------

    public void collect() {
        FileSet source = properties.getFileSet("source");
        helper.addResource(source);
        helper.addResource(CLASSPATH, resources.getPathGroupAsPath("compile"));

        if (properties.getBoolean("propogate")) {
            propogate();
        }
    }

    public void propogate() {
        helper.propogateResources();
        helper.propogateResources(CLASSPATH);
    }

    public void report() {
        helper.addReport();
        report(helper.getLocalResources(), helper.getLocalResources(CLASSPATH));
    }

    public void aggregateReport() {
        helper.addReport();
        report(helper.getAggregatedResources(), helper.getAggregatedResources(CLASSPATH));
    }

    public void report(ResourcesList sources, ResourcesList classpaths) {
        // Determine if vscaladoc is available and use it if it is
        Available available = new Available();
        available.setProject(resources.getProject());
        available.setClassname("org.scala_tools.vscaladoc.Main");

        Path scaladocClassPath = resources.getPathGroupAsPath("docs");
        available.setClasspath(scaladocClassPath);

        boolean vscaladoc = available.eval();

        Java scaladoc = plugin.createScalaCommand(vscaladoc ? "vscaladoc" : "scaladoc");
        scaladoc.setClassname(vscaladoc ? "org.scala_tools.vscaladoc.Main" : "scala.tools.nsc.ScalaDoc");

        scaladoc.setClasspath(scaladocClassPath);

        scaladoc.createArg().setValue("-d");

        File destDir = properties.getFile("destDir");
        utils.mkdir(destDir);
        scaladoc.createArg().setFile(destDir);

        setOptionValues(scaladoc, new String[] { "bottom", "doctitle", "footer", "header", "top", "windowtitle" });

        String options = properties.getString("options", null);

        if (options != null) {
            scaladoc.createArg().setLine(options); // For all unary options like -linksource, -nocomment etc
        }

        File stylesheet = properties.getFile("stylesheet", null);

        if (stylesheet != null) {
            scaladoc.createArg().setValue("-stylesheetfile");
            scaladoc.createArg().setFile(stylesheet);
        }

        Path sourcePath = new Path(resources.getProject());

        for (Iterator i = sources.getNested().iterator(); i.hasNext();) {
            FileSet source = (FileSet)i.next();
            sourcePath.append(new Path(resources.getProject(), source.getDir().getAbsolutePath()));
        }

        scaladoc.createArg().setValue("-classpath");
        scaladoc.createArg().setPath(mergePaths(classpaths));

        scaladoc.createArg().setValue("-sourcepath");
        scaladoc.createArg().setPath(sourcePath);

        for (Iterator i = sources.iterator(); i.hasNext();) {
            File file = ((FileResource)i.next()).getFile();
            scaladoc.createArg().setFile(file);
        }

        scaladoc.perform();
    }

    private void setOptionValues(Java command, String[] options) {
        for (int i = 0; i < options.length; i++) {
            String option = options[i];
            String value = properties.getString(option, null);

            if (value != null) {
                command.createArg().setValue("-" + option);
                command.createArg().setValue(value);
            }
        }
    }

    private Path mergePaths(ResourcesList paths) {
        Path merged = new Path(resources.getProject());

        for (Iterator i = paths.getNested().iterator(); i.hasNext();) {
            Path path = (Path)i.next();
            merged.add(path);
        }

        return merged;
    }
}
